/*
 * Copyright (c) 2014-2015 Luca Agostini, Alessandro Cantini, Alessandro Dignani
 *
 * This file is part of MeteoCal.
 *
 * MeteoCal is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package it.polimi.se2.agostini_cantini_dignani.meteocal.business;

import it.polimi.se2.agostini_cantini_dignani.meteocal.entity.Calendar;
import it.polimi.se2.agostini_cantini_dignani.meteocal.entity.Event;
import it.polimi.se2.agostini_cantini_dignani.meteocal.entity.User;
import org.jboss.arquillian.container.test.api.Deployment;
import org.jboss.arquillian.junit.Arquillian;
import org.jboss.shrinkwrap.api.ShrinkWrap;
import org.jboss.shrinkwrap.api.asset.EmptyAsset;
import org.jboss.shrinkwrap.api.spec.WebArchive;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;

import javax.ejb.EJB;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import java.util.ArrayList;
import java.util.List;

import static org.junit.Assert.*;

@RunWith(Arquillian.class)
public class EventManagerIT {

	private static User user;
	private static Event event;

	@EJB
	private UserManager um;

	@EJB
	private EventManager cut;

	@PersistenceContext
	private EntityManager em;

	@Deployment
	public static WebArchive createArchiveAndDeploy() {
		return ShrinkWrap.create(WebArchive.class)
				.addPackages(false, User.class.getPackage(), UserManager.class.getPackage())
				.addAsResource("test-persistence.xml", "META-INF/persistence.xml")
				.addAsWebInfResource(EmptyAsset.INSTANCE, "beans.xml");
	}

	@Before
	public void setUp() {
		user = TestHelper.getNewUser();
		event = TestHelper.getNewEvent();

		um.createUser(user);
		cut.createEvent(event, user);
	}

	@Test
	public void testCreateEvent() {
		Calendar calendar = user.getCalendar();

		assertEquals(event, em.find(Event.class, event.getEventId()));
		assertTrue(calendar.getEvents().contains(event));
		assertTrue(event.getParticipantCalendars().contains(calendar));
		assertEquals(user, event.getOwner());
	}

	@Test
	public void testRemoveEvent() {
		Calendar calendar = user.getCalendar();

		cut.removeParticipation(event, calendar);
		assertNull(em.find(Event.class, event.getEventId()));
		assertFalse(calendar.getEvents().contains(event));
	}

	@Test
	public void testAddParticipation() {
		User user2 = TestHelper.getNewUser();
		um.createUser(user2);

		cut.addParticipation(event, user2.getCalendar());

		assertTrue(event.getParticipantCalendars().size() == 2);
		assertTrue(event.getParticipantCalendars().contains(user.getCalendar()));
		assertTrue(event.getParticipantCalendars().contains(user2.getCalendar()));

		cut.removeParticipation(event, user2.getCalendar());
		assertTrue(event.getParticipantCalendars().size() == 1);
		assertTrue(event.getParticipantCalendars().contains(user.getCalendar()));
		assertFalse(event.getParticipantCalendars().contains(user2.getCalendar()));
	}

	@Test
	public void testEditEvent() {
		String newTitle = "a new title:" + event.getTitle();
		event.setTitle(newTitle);
		cut.editEvent(event, false);
		assertEquals(newTitle, event.getTitle());
		Event foundEvent = em.find(Event.class, event.getEventId());
		assertEquals(newTitle, event.getTitle());
	}

	@Test
	public void testAddInvitation() {
		User u2 = TestHelper.getNewUser();
		um.createUser(u2);

		cut.inviteUserToEvent(event, u2);
		cut.editEvent(event, false);

		assertTrue(event.getInvitedUsers().contains(u2));
		assertTrue(event.getInvitedUsers().size() == 1);
		Event foundEvent = em.find(Event.class, event.getEventId());
		assertTrue(foundEvent.getInvitedUsers().contains(u2));
		assertTrue(foundEvent.getInvitedUsers().size() == 1);
	}

	@Test
	public void testRemoveInvitation() {
		User u2 = TestHelper.getNewUser();
		um.createUser(u2);
		cut.inviteUserToEvent(event, u2);
		cut.editEvent(event, false);

		cut.acceptInvitation(u2, event);
		cut.editEvent(event, false);

		assertFalse(event.getInvitedUsers().contains(u2));
		assertTrue(event.getInvitedUsers().isEmpty());
		Event foundEvent = em.find(Event.class, event.getEventId());
		assertFalse(foundEvent.getInvitedUsers().contains(u2));
		assertTrue(foundEvent.getInvitedUsers().isEmpty());
	}

	@Test
	public void testFindAll() {
		final int EVENTS_TO_CREATE = 10;
		List<Event> createdEvents = new ArrayList<Event>();

		int initialSize = cut.findAll().size();

		for (int i = 0; i < EVENTS_TO_CREATE; i++) {
			List<Event> allEvents = cut.findAll();
			assertTrue(allEvents.size() == initialSize + i);

			Event newEvent = TestHelper.getNewEvent();
			cut.createEvent(newEvent, user);
			createdEvents.add(newEvent);

			allEvents = cut.findAll();
			assertTrue(allEvents.contains(event));
			assertTrue(allEvents.contains(newEvent));
			assertTrue(allEvents.size() == initialSize + i + 1);
		}

		for (int i = EVENTS_TO_CREATE - 1; i >= 0; i--) {
			Event e = createdEvents.get(i);

			cut.removeParticipation(e, user.getCalendar());
			List<Event> allEvents = cut.findAll();
			assertFalse(allEvents.contains(e));
			assertTrue(allEvents.size() == initialSize + i);
		}
	}
}